package com.lazy.lib.lang;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * 封装一个线程安全的队列
 * 如果队列设置大小，则为有界队列，如果大于该队列的数据，将队列头移除
 *
 * @param <T>
 *
 * @author grind
 * @date Mar 13, 2014 3:12:22 PM
 * @version 1.0
 */
public class BoundedQueue<T> {
    protected Logger logger = LoggerFactory.getLogger(this.getClass());
    
    protected static final int DEFAULT_CAPACITY = 180 * 1000; // 1000台车机缓冲3分钟
    protected BlockingQueue<T> dataQueue;
    // 队列的容量, 大于该大小, 将移除
    protected int capacity = DEFAULT_CAPACITY; //Integer.MAX_VALUE;

    protected final String name;
    
    public BoundedQueue() {
        this("default", DEFAULT_CAPACITY);
    }

    public BoundedQueue(final String name) {
        this(name, DEFAULT_CAPACITY);
    }

    public BoundedQueue(final String name, final int capacity) {
        if (capacity < Integer.MAX_VALUE) {
            dataQueue = new LinkedBlockingQueue<T>(capacity+1);
        } else {
            dataQueue = new LinkedBlockingQueue<T>(Integer.MAX_VALUE);
        }
        this.capacity = capacity;
        this.name = "Q_" + name;
    }

    public BlockingQueue<T> getDataQueue(){
        return dataQueue;
    }

    // 数据队列的操作
    public void offerDataQueue(T data) {
        try{
            // 如果超过最大次数-1
            if (dataQueue.size() >= capacity) {
                logger.warn("removed the head of dataQueue for it's full. " + dataQueue.size());
                dataQueue.poll();
            }
            if(!dataQueue.offer(data, 10, TimeUnit.SECONDS)) {
                logger.warn("dataQueue is full. " + dataQueue.size());
            }

            if (logger.isDebugEnabled()) { logger.debug("Queue_" + name + "  now size:" + dataQueue.size()); }
        }catch(InterruptedException e){
            logger.error("Offer message error: " +  e.getMessage());
        }
    }
    
    public T takeDataQueue() {
        try{
            return dataQueue.take();
        }catch(InterruptedException e){
            logger.error("Take object from Queue error:" + e.getMessage());
        }
        return null;
    }
    

    /** 从队列中取出maxElements的数据, 并放入到list中, 如果队列数据
     * 小于maxElements, 那么全部取出,返回值为实际取到的数据
     * 这个是非阻塞的取出
     */
    public int drainTo(List<T> list, int maxElements) {
        return dataQueue.drainTo(list, maxElements);
    }
    
    /**
     * Returns the number of elements in this queue.
     *
     * @return the number of elements in this queue
     */
    public int size() {
        return dataQueue.size();
    }
    
    public int remainingCapacity() {
        return dataQueue.remainingCapacity();
    }
    
    /**
     * Atomically removes all of the elements from this queue.
     * The queue will be empty after this call returns.
     */
    public void clear() {
        dataQueue.clear();
    }
    
    public boolean isEmpty() {
        return dataQueue.isEmpty();
    }
    
    public static void main(String[] args) {
        BoundedQueue<String> testQueue = new BoundedQueue<String>("test", 5);

        testQueue.offerDataQueue("test1");
        testQueue.offerDataQueue("test2");
        testQueue.offerDataQueue("test3");
        testQueue.offerDataQueue("test4");
        System.out.println(testQueue.size());
        testQueue.offerDataQueue("test5");
        System.out.println(testQueue.size());
        testQueue.offerDataQueue("test6");
        System.out.println(testQueue.size()); // 结果应该是5
        System.out.println(testQueue.takeDataQueue()); // 获取的应该是test2

        System.out.println("testQueue size:"  + testQueue.size());
        List<String> list = new ArrayList<String>();
        int n = testQueue.drainTo(list, 2);
        System.out.println("drainTo real count:"  + n);
        System.out.println("testQueue size:"  + testQueue.size());
        
    }

}
